人工智慧實務工作坊-手把手教你深度學習實務

真實世界的卷積神經網路開發

林嶔 (Lin, Chin)

第一節:圖像識別的深度學習研究(1)

– 事實上我們從事後的角度來說,深度學習是一個需要數據量才能體現出的強大算法,假設我們一直沒有足夠的數據量,那深度學習將永無抬頭之日!

F8_5

F8_6

F8_7

第一節:圖像識別的深度學習研究(2)

– 下面這張圖是每一年的冠軍演算法,我們可以看到在2012年以前,這項比賽大多是由SVM、隨機森林等方法獲得冠軍,但自2012年以來卷積神經網路就席捲了ILSVRC之後所有的冠軍。

F8_8

第二節:利用經典模型的model進行預測(1)

– 除此之外,由於ImageNet上的比賽是對圖像做1000類別的分類,但我們並不清楚是哪1000個類別,model裡面的chinese synset.txt描述著第幾個類別是什麼的資訊。

library(OpenImageR)

img = readImage('image/test.jpg') 
resized_img = resizeImage(img, 224, 224, method = 'bilinear')

imageShow(resized_img)

norm_img = resized_img
norm_img = norm_img * 255
norm_img = norm_img - 128

dim(norm_img) = c(224, 224, 3, 1)

第二節:利用經典模型的model進行預測(2)

library(mxnet)

inception_model = mx.model.load("model/Inception-BN", 126)

pred_prob  = predict(inception_model, norm_img)
which.max(pred_prob)
## [1] 3
synsets <- readLines('model/chinese synset.txt', encoding = 'UTF-8')

pred_prob <- as.numeric(pred_prob)
names(pred_prob) <- synsets
pred_prob <- sort(pred_prob, decreasing = TRUE)
pred_prob <- formatC(pred_prob, 4, format = 'f')

head(pred_prob, 5)
##             n01484850 大白鯊               n03045698 斗篷 
##                     "0.8162"                     "0.0591" 
##         n03916031 香水(瓶) n02071294 殺人鯨,逆戟鯨,虎鯨 
##                     "0.0125"                     "0.0091" 
##               n03388043 噴泉 
##                     "0.0080"

第三節:分享這個模型的預測功能(1)

– 其中global.R描述了模型及標籤檔案的位置,以及定義了前處理的函數

– ui.R負責定義使用者介面

– server.R中定義了程式對於使用者動作的相對應反應

F8_9

第三節:分享這個模型的預測功能(2)

F8_10

第四節:訓練一個模型來預測自己的資料(1)

– 我們有個想法,能不能使用這些經典模型的參數當作初始權重,並在這個基礎上訓練網路完成我們的任務目標。這個想法稱作轉移特徵學習(Transfer learning),而這個想法是基於人類通常具有舉一反三的能力,舉例來說一個剛入學的醫學系學生他們僅有接受過高中程度的基礎訓練,並未接受過任何醫學專業領域的訓練,但他們的學習因為是基於高中的基礎之上,因此即使醫學專業相當艱深也能相當快的學會。

– 一般來說,有使用轉移特徵學習的概念先將網路在大資料上學習(主題可以與目標任務幾乎無關),而後再到目標任務中訓練,其準確度會更好。

F8_39

第四節:訓練一個模型來預測自己的資料(2)

– 舉例來說,我們可以定義我們要整個Inception-BN除了最後一個全連接層外的所有結構,只把最後一層的FC從分1000類轉變成分2類:

library(mxnet)

inception_model = mx.model.load("model/Inception-BN", 126)

all_layers = inception_model$symbol$get.internals()
flatten_pos = which(all_layers$outputs == 'flatten_output')
flatten_output = all_layers$get.output(flatten_pos)

fc1 <- mx.symbol.FullyConnected(data = flatten_output, num_hidden = 2, name = 'fc1')
softmax <- mx.symbol.SoftmaxOutput(data = fc1, name = 'softmax')

第四節:訓練一個模型來預測自己的資料(3)

Train_img = array(0, dim = c(224, 224, 3, 200))
Train.y = array(0, dim = c(2, 200))

for (i in 1:100) {
  
  # Cat
  img = readImage(paste0('Dogs vs. Cats/cat.', i, '.jpg'))
  resized_img = resizeImage(img, 224, 224, method = 'bilinear')
  Train_img[,,,2*i-1] = resized_img
  Train.y[1,2*i-1] = 1
  
  # Dog
  img = readImage(paste0('Dogs vs. Cats/dog.', i, '.jpg'))
  resized_img = resizeImage(img, 224, 224, method = 'bilinear')
  Train_img[,,,2*i] = resized_img
  Train.y[2,2*i] = 1
  
}

Train_img = Train_img * 255 - 128

第四節:訓練一個模型來預測自己的資料(4)

– 接著,我們在開始訓練之前需要取得模型權重參數,我們可以將最後一層以外的部分填入Inception-BN的參數,並以這為基礎開始訓練任務:

mx.set.seed(0)

new_arg = mxnet:::mx.model.init.params(symbol = softmax,
                                       input.shape = list(data = c(224, 224, 3, 20)),
                                       output.shape = NULL,
                                       initializer = mxnet:::mx.init.uniform(0.01),
                                       ctx = mx.cpu())

for (i in 1:length(new_arg$arg.params)) {
  pos = which(names(inception_model$arg.params) == names(new_arg$arg.params)[i])
  if (all.equal(dim(inception_model$arg.params[[pos]]), dim(new_arg$arg.params[[i]])) == TRUE) {
    new_arg$arg.params[[i]] = inception_model$arg.params[[pos]]
  }
}

for (i in 1:length(new_arg$aux.params)) {
  pos = which(names(inception_model$aux.params) == names(new_arg$aux.params)[i])
  if (all.equal(dim(inception_model$aux.params[[pos]]), dim(new_arg$aux.params[[i]])) == TRUE) {
    new_arg$aux.params[[i]] = inception_model$aux.params[[pos]]
  }
}

第四節:訓練一個模型來預測自己的資料(5)

my.eval.metric.mlogloss <- mx.metric.custom(
  name = "m-logloss", 
  function(real, pred) {
    real1 = as.numeric(as.array(real))
    pred1 = as.numeric(as.array(pred))
    pred1[pred1 <= 1e-6] = 1e-6
    pred1[pred1 >= 1 - 1e-6] = 1 - 1e-6
    return(-mean(real1 * log(pred1), na.rm = TRUE))
  }
)

FIXED_NAMES = names(new_arg$arg.params)
FIXED_NAMES = FIXED_NAMES[1:276]
FIXED_NAMES = c(FIXED_NAMES, names(new_arg$aux.params))

mx.set.seed(0)

my_model = mx.model.FeedForward.create(symbol = softmax,
                                       X = Train_img, y = Train.y,
                                       optimizer = "sgd", learning.rate = 0.001, momentum = 0.9,
                                       array.batch.size = 10, num.round = 20,
                                       arg.params = new_arg$arg.params, aux.params = new_arg$aux.params,
                                       fixed.param = FIXED_NAMES,
                                       ctx = mx.cpu(),
                                       eval.metric = my.eval.metric.mlogloss)
my_model$arg.params = append(my_model$arg.params, new_arg$arg.params[1:276])
my_model$aux.params = new_arg$aux.params

第四節:訓練一個模型來預測自己的資料(6)

img = readImage('Dogs vs. Cats/test_cat.3.jpg')
resized_img = resizeImage(img, 224, 224, method = 'bilinear')

imageShow(resized_img)

norm_img = resized_img
norm_img = norm_img * 255
norm_img = norm_img - 128

dim(norm_img) = c(224, 224, 3, 1)

pred_prob  = predict(my_model, norm_img)
pred_prob
##             [,1]
## [1,] 0.993675292
## [2,] 0.006324741

第四節:訓練一個模型來預測自己的資料(7)

img = readImage('Dogs vs. Cats/test_dog.3.jpg')
resized_img = resizeImage(img, 224, 224, method = 'bilinear')

imageShow(resized_img)

norm_img = resized_img
norm_img = norm_img * 255
norm_img = norm_img - 128

dim(norm_img) = c(224, 224, 3, 1)

pred_prob  = predict(my_model, norm_img)
pred_prob
##           [,1]
## [1,] 0.4262857
## [2,] 0.5737143

結語

– 如果你想把自己訓練的模型放到剛剛的App內,還要記得改變chinese synset.txt檔案喔!

– 另外,深度學習的潛力可不僅僅只有圖像辨識任務,其他包含物件識別、物件分割、圖像生成,甚至是語言模型,都是可以做出來的,這也值得有興趣的人再進一步學習!